package com.wchat.serviceimpl;

import com.wchat.configurer.RedisPoolConfig;
import com.wchat.converter.UserLoginDTOConverter;
import com.wchat.dataobject.UserEntity;
import com.wchat.dto.UserLoginDTO;
import com.wchat.dto.UserRegisterDTO;
import com.wchat.enums.ResultEnum;
import com.wchat.exceptions.ServiceException;
import com.wchat.repository.UserRepository;
import com.wchat.repository.VerifyCodeRepository;
import com.wchat.service.AuthUtilService;
import com.wchat.service.UserService;
import com.wchat.utils.ReqexUtils;
import com.wchat.vo.ForgetPasswordVo;
import com.wchat.vo.UserLoginVo;
import org.apache.commons.lang3.StringUtils;
import org.omg.CORBA.INTERNAL;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.RequestBody;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.text.MessageFormat;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl implements UserService {

    public static final String DEFAULT_IMAGE = "https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=4000895298,4180128752&fm=27&gp=0.jpg";

    @Autowired private UserRepository userRepository;

    @Autowired private VerifyCodeRepository verifyCodeRepository;

    @Autowired private SendVerifyCodeImpl userService;

    @Autowired private  AuthUtilService authUtilService;

    private static final String SALT = "hsjhdj3hjsdfhjfhsjfhjs3333jrh3h3s";

    private final Integer expireTime = 60 * 24 * 30 * 1000;

    Jedis jedis = RedisPoolConfig.getJedis();

    /**
     * 用户注册
     * @param phoneNumber 手机号
     * @param verifyCode 验证码
     * @return
     */
    @Override
    public UserRegisterDTO userRegisterByPhone(String phoneNumber, Integer verifyCode,String password, HttpServletRequest request) {

        UserEntity user = getTbUserByPhoneNumber(phoneNumber);
        if(null != user){
                                                                         // 该用户已经注册
            throw new ServiceException(ResultEnum.USER_IS_REGISTER.getCode(),ResultEnum.USER_IS_REGISTER.getValue());
        }if(!userService.checkoutVerifyCode(phoneNumber,verifyCode)){    // 校验验证码
            throw new ServiceException(ResultEnum.VERIFYCODE_IS_ERROR.getCode(),ResultEnum.VERIFYCODE_IS_ERROR.getValue());
        }if(StringUtils.isBlank(password)){                              //  密码不能为空
            throw new ServiceException(ResultEnum.PASS_NOT_ALLOW_NULL.getCode(),ResultEnum.PASS_NOT_ALLOW_NULL.getValue());
        }
        //verifyCodeRepository.updateIsUsedByPhoneNumber(1,phoneNumber);
        UserEntity newUser = getDefaultUser(phoneNumber,password);
        userRepository.save(newUser);
        user = getTbUserByPhoneNumber(phoneNumber);
        if(null == user ){
            return null;
        }
        UserRegisterDTO userRegisterDTO = new UserRegisterDTO();
        userRegisterDTO.setMsg("亲，成功注册需要两步，你已经完成第一步，手机认证。第二步，您可以登陆我们的公众号，报名参加我们浪漫的现场活动，邂逅您心中的佳人，并现场完成实名认证");
        userRegisterDTO.setIsNew(1);
        request.getSession().setAttribute(AuthUtilService.sessionKey,authUtilService.createAuthInfo(user.getUserId(),AuthUtilService.UserType.USER));
        userRegisterDTO.setToken(authUtilService.createJwt(authUtilService.createAuthInfo(user.getUserId(),AuthUtilService.UserType.USER)));
        return userRegisterDTO;
    }

    /**
     * 用户手机登录
     * @param userLoginVo
     * @param request
     * @return
     */
    @Override
    public UserLoginDTO userLoginByPhone(@RequestBody UserLoginVo userLoginVo, HttpServletRequest request) {

        UserEntity user = new UserEntity();
        //校验手机号
        if (!ReqexUtils.checkMobile(userLoginVo.getPhoneNumber())) {
            throw new ServiceException(ResultEnum.MOBILE_ERROR.getCode(),ResultEnum.MOBILE_ERROR.getValue());
        }
        //判断用户是否注册过,如果没有注册过，直接注册并绑定用户
        user.setPhoneNumber (userLoginVo.getPhoneNumber());
        user = userRepository.findByPhoneNumber(user.getPhoneNumber());
        if (null == user) {
            //注册用户===绑定并登陆===== 如果用户没有查询到
            throw new ServiceException(ResultEnum.USER_IS_NOTREGISTER.getCode(),ResultEnum.USER_IS_NOTREGISTER.getValue());
            //return registerUserAndBindAndLogin(userLoginVo, request);
        }    // 如果查询到该用户 直接绑定userLoginService.bindUser(getThirdBindIngParam(userInfoParam));
          if(user.getUserId() != 0 && StringUtils.isBlank(user.getOpenid())){
                // 如果该用户应注册过 但是没绑定 直接走绑定 然后登录
              if(!user.getPassword().equals(generateEncryptPassword(userLoginVo.getPasswod()))){   //  密码不正确
                  throw new ServiceException(ResultEnum.PASSWORD_IS_ERROR.getCode(),ResultEnum.PASSWORD_IS_ERROR.getValue());
              }
              return bindWexin(userLoginVo,user.getUserId());
          }
        if(!user.getPassword().equals(generateEncryptPassword(userLoginVo.getPasswod()))){   //  密码不正确
            throw new ServiceException(ResultEnum.PASSWORD_IS_ERROR.getCode(),ResultEnum.PASSWORD_IS_ERROR.getValue());
        }
         UserLoginDTO  userLoginDTO =  UserLoginDTOConverter.userLoginDTOConveter(userRepository.findOne(user.getUserId()));
         request.getSession().setAttribute(AuthUtilService.sessionKey,authUtilService.createAuthInfo(user.getUserId(),AuthUtilService.UserType.USER));
         try( Jedis jedis = RedisPoolConfig.getJedis()){
                 String userTokenKey = genUserTokenKey(String.valueOf(userLoginDTO.getUserId()));
                 String token = authUtilService.createJwt(authUtilService.createAuthInfo(userLoginDTO.getUserId(),AuthUtilService.UserType.USER),60);
                jedis.set(userTokenKey,token);
                jedis.expire(userTokenKey,expireTime);  //user_token:user_43 key
                userLoginDTO.setToken(token);
         }
         return userLoginDTO;

    }

    /**
     * 忘记密码
     * @param forgetPasswordVo
     */
    @Override
    public void forgetPass(ForgetPasswordVo forgetPasswordVo) {

        UserEntity user = getTbUserByPhoneNumber(forgetPasswordVo.getPhoneNumber());
        if (user == null)
            throw new ServiceException(ResultEnum.CURRENT_USER_NULL.getCode(),ResultEnum.CURRENT_USER_NULL.getValue()); // 用户存
        if(!userService.checkoutVerifyCode(forgetPasswordVo.getPhoneNumber(),forgetPasswordVo.getVerifyCode()))
            throw new ServiceException(ResultEnum.VERIFYCODE_IS_ERROR.getCode(),ResultEnum.VERIFYCODE_IS_ERROR.getValue());
        if(StringUtils.isBlank(forgetPasswordVo.getNewPass())){
            throw new ServiceException(ResultEnum.PASS_NOT_ALLOW_NULL.getCode(),ResultEnum.PASS_NOT_ALLOW_NULL.getValue());
        }
        user.setPassword(generateEncryptPassword(forgetPasswordVo.getNewPass()));
        userRepository.updatePassByUserId(generateEncryptPassword(forgetPasswordVo.getNewPass()),user.getUserId()); //   更新用户

    }

    /**
     * 添加关注 UserIdB
     * @param userIdA
     * @param userIdB
     */
    @Override
    public Long addFollow(Integer userIdA, Integer userIdB) {
        if(userIdA == null || userIdB == null){
            throw  new ServiceException(ResultEnum.ADD_FOLLOW_ERROR.getCode(),ResultEnum.ADD_FOLLOW_ERROR.getValue());  //  添加关注失败
        }
        jedis.sadd(genFollowKey(userIdA),String.valueOf(userIdB)); //  将userIdB 添加到 userIdA 关注列表中
        jedis.sadd(genFansKey(userIdB),String.valueOf(userIdA));    // 将userIdA 添加到userIdB的粉丝列表中
        return jedis.scard(genFollowKey(userIdA)); //  获取我的关注数
    }

    /**
     * 生成 关注列表key
     * @param userIdA
     * @return
     */
    private String genFollowKey(Integer userIdA){
        return MessageFormat.format("follow:{0}",userIdA);
    }

    /**
     * 生成粉丝key
     * @param userIdB
     * @return
     */
    private String genFansKey(Integer userIdB){
        return MessageFormat.format("fans:{0}",userIdB);
    }
    /**
     * 取消关注 UserIdB
     * @param userIdA
     * @param userIdB
     */
    @Override
    public void cancleFollow(Integer userIdA, Integer userIdB) {
        jedis.srem(genFollowKey(userIdA),String.valueOf(userIdB)); //  将userIdB 添加到 userIdA 关注列表中
        jedis.srem(genFansKey(userIdB),String.valueOf(userIdA));    // 将userIdA 添加到userIdB的粉丝列表中

    }

    /**
     * 获取关注列表
     * @param userIdA
     * @return
     */
    @Override
    public List<UserEntity> followList(Integer userIdA) {
        if(userIdA == null) {
            throw new ServiceException(ResultEnum.GET_FOLLOW_LIST_ERROR.getCode(), ResultEnum.GET_FOLLOW_LIST_ERROR.getValue());  // 获取关注列表失败
        }
        Set<String> userIds = jedis.smembers(genFollowKey(userIdA));  //  获取用户id集合
        List<Integer> ids = userIds.stream().map(userid -> Integer.valueOf(userid)).collect(Collectors.toList());
        return userRepository.findAll(ids);
    }

    /**
     * 用户注册绑定登录
     * @param userLoginVo
     * @param request
     * @return
     */
    private UserLoginDTO registerUserAndBindAndLogin(UserLoginVo userLoginVo,HttpServletRequest request){
           if(StringUtils.isBlank(userLoginVo.getOpenid()) || StringUtils.isBlank(userLoginVo.getPhoneNumber())){
               throw new ServiceException(ResultEnum.REGISTER_PARAM_IS_ERROR.getCode(),ResultEnum.REGISTER_PARAM_IS_ERROR.getValue());
           }
           if(getTbUserByPhoneNumber(userLoginVo.getPhoneNumber()) != null){  // 手机号已经注册
               throw new ServiceException(ResultEnum.PHONENUMBER_IS_REGISTER.getCode(),ResultEnum.PHONENUMBER_IS_REGISTER.getValue());
           }
           UserEntity user = getDefaultUser(userLoginVo.getPhoneNumber(),"");// 新用户注册成功 接下来是绑定
           Integer userId = user.getUserId();
           return  bindWexin(userLoginVo,userId);
    }

    /**
     * 绑定微信
     * @param userLoginVo
     * @param userId
     * @return
     */
    private UserLoginDTO bindWexin(UserLoginVo userLoginVo, Integer userId) {
        UserEntity user = userRepository.findOne(userId);

        if(StringUtils.isNotBlank(user.getOpenid()) && StringUtils.isNotBlank(user.getPhoneNumber())){
            throw new ServiceException(ResultEnum.USER_IS_BINED.getCode(),ResultEnum.USER_IS_BINED.getValue()); //  该用户已经绑定
        }
        int result =userRepository.updateByUserId(userLoginVo.getNickName(),userLoginVo.getGender(),
                userLoginVo.getHeadImage(),userLoginVo.getOpenid(),userLoginVo.getCity(),userLoginVo.getProvince(),
                userLoginVo.getCountry(),userLoginVo.getLongitude(),userLoginVo.getLatitude(),userId);
        if(result < 1){
            throw new ServiceException(ResultEnum.WEIXIN_BIND_EROOR.getCode(),ResultEnum.WEIXIN_BIND_EROOR.getValue()); // 微信绑定失败
        }
        return UserLoginDTOConverter.userLoginDTOConveter(userRepository.findOne(userId));
    }

    //  默认注册用户
    private UserEntity getDefaultUser(String phoneNumber,String password) {
        UserEntity userEntity= new UserEntity();
        userEntity.setCuteName("邂逅"+phoneNumber.substring(phoneNumber.length() - 4));
        userEntity.setGender(0);
        userEntity.setAge(0);
        userEntity.setHeight(0);
        userEntity.setResidence("");
        userEntity.setDegree("");
        userEntity.setPosition("");
        userEntity.setHeadImage(DEFAULT_IMAGE);
        userEntity.setPhoneNumber(phoneNumber);
        userEntity.setLongitude("");
        userEntity.setLatitude("");
        userEntity.setOpenid("");
        userEntity.setPassword(generateEncryptPassword(password)); //  默认密码
        userEntity.setCity("");
        userEntity.setProvince("");
        userEntity.setCountry("");
        userEntity.setIsNew(1); // 默认新用户
        userRepository.save(userEntity);
        return userEntity;
    }

    private UserEntity getTbUserByPhoneNumber(String phoneNumber) {
       return userRepository.findByPhoneNumber(phoneNumber);
    }


    /**
     * 将明文密码进行加密
     *
     * @param clearPassword 明文密码
     * @return 加密后的密码
     */
    private String generateEncryptPassword(String clearPassword) {
        return DigestUtils.md5DigestAsHex((SALT + DigestUtils.md5DigestAsHex(clearPassword.getBytes())).getBytes());
    }


    private  String genUserTokenKey(String userKey) {
        return MessageFormat.format("user_token:user_{0}", userKey);
    }
}








